// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <memory>
#include <sstream>
#include <string>
#include <utility>

#include "coin2/exchange/base/order/rate_tracker.h"

namespace coin2::exchange::phemex::api_util {

struct RateLimitInfo {
  explicit RateLimitInfo(int32_t rl) : rate_limit(rl) {}
  std::string DebugString() const {
    std::stringstream ss;
    ss << "RateLimitInfo: \n";
    ss << "rate_limit: " << rate_limit << "\n";
    ss << "rate_limit_consumed: " << rate_limit_consumed << "\n";
    ss << "rate_limit_remain: " << rate_limit_remain << "\n";
    ss << "enable_time: " << enable_time << "\n";
    ss << "success : " << success << "\n";
    return ss.str();
  }

  int32_t rate_limit{0};
  int32_t rate_limit_consumed{0};
  int32_t rate_limit_remain{0};
  int64_t enable_time{0};
  bool success{false};
};

class PhemexRateTracker : public coin2::exchange::base::order::IRateTracker {
 public:
  using RateTracker = coin2::exchange::base::order::RateTracker;
  using ActionType = coin2::exchange::base::order::IRateTracker::ActionType;
  using RateLimitReportWriter = coin2::exchange::base::order::RateLimitReportWriter;
  using FixedWindowRateTracker = coin2::exchange::base::order::FixedWindowRateTracker;
  using RateLimitInfoSpotPhemex = coin2::exchange::order::RateLimitInfoSpotPhemex;
  using RateLimitInfoFuturesPhemex = coin2::exchange::order::RateLimitInfoFuturesPhemex;

 public:
  explicit PhemexRateTracker(
      const MarketExchangeApi& mea,
      const coin2::exchange::order::OrderConnectionConfig& cfg);

  bool HasEnoughRateLimit(int64_t timestamp, ActionType action_type) override;
  void Push(int32_t num_reqs, int64_t timestamp, ActionType action_type) override;
  void ParseRateLimitInfo(const std::shared_ptr<AsioHttpContext>&, ActionType) override {}
  void SetRateLimitInfo(int32_t rate_limit, int32_t rate_limit_remaining) override { CHECK(false); }
  void SetRateLimitInfoString(const google::protobuf::Message* message) override;
  void WriteRateLimitReportMessage(OrderLoggerCB callback) override;
  double GetMaxRateUsedRatio(int64_t timestamp, ActionType action_type) override;

  void UpdateRateLimitSpotOrder(int32_t rate_limit_remain);
  void UpdateRateLimitContract(int32_t rate_limit_remain);
  void UpdateRateLimitOthers(int32_t rate_limit_remain);
  void UpdateSpotOrderEnableTime(int64_t enable_time) { enable_time_spotorder_ = enable_time; }
  void UpdateOthersEnableTime(int64_t enable_time) { enable_time_others_ = enable_time; }
  void UpdateContractEnableTime(int64_t enable_time) { enable_time_contract_ = enable_time; }

 private:
  void InitRateTracker(
      RateLimitInfoSpotPhemex* rate_config,
      std::string_view mea_str,
      std::string_view example);
  void InitRateTracker(
      RateLimitInfoFuturesPhemex* rate_config,
      std::string_view mea_str,
      std::string_view example);
  bool CheckEnableTime(int64_t timestamp, ActionType action_type);
  bool CheckRateLimit(int64_t timestamp, ActionType action_type);

 private:
  int64_t enable_time_spotorder_ = 0;
  int64_t enable_time_others_ = 0;
  int64_t enable_time_contract_ = 0;
  std::unique_ptr<FixedWindowRateTracker> rate_tracker_spotorder_;
  std::unique_ptr<FixedWindowRateTracker> rate_tracker_contract_;
  std::unique_ptr<FixedWindowRateTracker> rate_tracker_others_;
  std::unique_ptr<RateLimitReportWriter> rate_limit_report_writer_ = {};
};

}  // namespace coin2::exchange::phemex::api_util
